package com.fuyin.controller;

import java.io.Serializable;
import java.util.Objects;
import java.util.UUID;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import com.fuyin.commons.response.BaseResponse;
import com.fuyin.commons.response.ErrorCode;
import com.fuyin.commons.utils.MyUtils;
import com.fuyin.dao.UserDao;
import com.fuyin.entity.PmValidate;
import com.fuyin.entity.User;
import com.fuyin.service.ValidateServiceImpl;
import com.fuyin.service.user.UserService;

import io.swagger.annotations.*;
import lombok.Data;

/**
 * @author yuanxilan (yuanxilan@keep.com)
 * @Description
 * @date 2021年11月18日 4:52 下午
 * @since
 */
@Api(tags = "通过邮件修改密码相关api")
@RestController
@RequestMapping(value = "/validate")
public class ValidateController {

    @Autowired
    private ValidateServiceImpl validateService;

    @Autowired
    private UserService userService;

    //发送邮件的类
    @Autowired
    private JavaMailSender mailSender;

    @Autowired
    private UserDao userDao;

    @Autowired
    private PasswordEncoder passwordEncoder;

    //这里使用的是我们已经在配置问价中固定了的变量值,也就是通过这个邮箱向目标邮箱发送重置密码的邮件
    @Value("${spring.mail.username}")
    private String from;

    @Value("${password.pattern}")
    private String passwordPattern;

    /**
     * 发送忘记密码邮件请求，每日申请次数不超过20次，每次申请间隔不低于1分钟
     *
     * @param email
     * @param request
     * @return
     */
    @ApiOperation(value = "发送忘记密码邮件", notes = "发送忘记密码邮件")
    @PostMapping("/sendValidationEmail")
    @ResponseBody
    @ApiResponses({
            @ApiResponse(code = 200, message = "发送成功"),
            @ApiResponse(code = 419, message = "该邮箱所属用户不存在"),
            @ApiResponse(code = 406, message = "操作过于频繁")
    })
    public BaseResponse sendValidationEmail(@ApiParam("邮箱地址") @RequestParam("email") String email, HttpServletRequest request) throws MessagingException {
        if (StringUtils.isBlank(email)) {
            return BaseResponse.error(ErrorCode.BAD_REQUEST, "邮箱地址不能为空");
        }
        ResetInfo info = new ResetInfo();
        User user = userService.findUserByEmail(email);
        if (Objects.isNull(user)) {
            return BaseResponse.error(ErrorCode.EMAIL_USER_NOT_FOUND, "该邮箱所属用户不存在");
        } else {
            if (validateService.sendValidateLimitation(email, 20, 1)) {
                // 若允许重置密码，则在pm_validate表中插入一行数据，带有token
                PmValidate pmValidate = new PmValidate();
                validateService.insertNewResetRecord(pmValidate, user, UUID.randomUUID().toString(), "passwordReset");
                // 设置邮件内容
//                String appUrl = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort();
                String appUrl = "http://120.77.71.117:8076/resetPwd";
                MimeMessage mimeMessage = mailSender.createMimeMessage();
                // multipart模式
                MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true, "utf-8");
                mimeMessageHelper.setTo(email);
                mimeMessageHelper.setFrom(from);
                mimeMessageHelper.setSubject("重置密码");
                StringBuilder sb = new StringBuilder();
                sb.append("<html><head></head>");
                sb.append("<body><h1>点击下面的链接重置密码</h1>" +
                        "<a href = " + appUrl + "?token=" + pmValidate.getResetToken() + ">" + appUrl + "?token=" + pmValidate.getResetToken() + "</a></body>");
                sb.append("</html>");
                // 启用html
                mimeMessageHelper.setText(sb.toString(), true);
                validateService.sendPasswordResetEmail(mimeMessage);
//                if (request.getScheme().contains("http")) {
//                    return BaseResponse.success();
//                }
//                SimpleMailMessage passwordResetEmail = new SimpleMailMessage();
//                passwordResetEmail.setFrom(from);
//                passwordResetEmail.setTo(email);
//                passwordResetEmail.setSubject("忘记密码");
//                passwordResetEmail.setText("您正在申请重置密码，请点击此链接重置密码: \n" +appUrl + "/validate/resetPassword?token=" + validateDao.getResetToken());
//                validateService.sendPasswordResetEmail(passwordResetEmail);

                info.setLink(appUrl + "?token=" + pmValidate.getResetToken());
                info.setToken(pmValidate.getResetToken());
                info.setMessage("邮件已经发送");
            } else {
                return BaseResponse.error(ErrorCode.OPERATION_FREQUENCY, "操作过于频繁，请稍后再试！");
            }
        }
        return BaseResponse.success(info);
    }

    @Data
    private class ResetInfo implements Serializable {

        private static final long serialVersionUID = -3476632722345520920L;

        private String token;

        @ApiModelProperty("重置密码链接")
        private String link;

        @ApiModelProperty("其它信息，如：邮件已经发送")
        private String message;
    }

    /**
     * 将url的token和数据库里的token匹配，成功后便可修改密码，token有效期为5分钟
     *
     * @return
     */
    @ApiOperation(value = "重置密码,邮箱中的token有效时间为5分钟,每天每个用户最多发10次邮件", notes = "重置密码")
    @PostMapping(value = "/resetPassword")
    @ResponseBody
    @ApiResponses({
            @ApiResponse(code = 200, message = "修改成功"),
            @ApiResponse(code = 400, message = "参数不能为空"),
            @ApiResponse(code = 401, message = "链接失效"),
            @ApiResponse(code = 422, message = "新密码不符合规范")
    })
    public BaseResponse resetPassword(@RequestBody PasswordExchange passwordExchange) {
        String token = passwordExchange.getToken();
        String password = passwordExchange.getPassword();
        MyUtils.checkParams("token 和 密码不能为空", token, password);
        // 通过token找到validate记录
        PmValidate pmValidate = validateService.findUserByResetToken(token);
        if (Objects.isNull(pmValidate)) {
            return BaseResponse.error(ErrorCode.BAD_REQUEST, "该重置请求不存在");
        } else {
            if (validateService.validateLimitation(pmValidate.getEmail(), Long.MAX_VALUE, 5, token)) {
                String userName = pmValidate.getUserName();
                if (!password.matches(passwordPattern)) {
                    return BaseResponse.error(ErrorCode.PASSWORD_NOT_MATCH_PATTERN, "新密码不符合规范");
                }
                userDao.updatePassword(userName, passwordEncoder.encode(password));
            } else {
                return BaseResponse.error(ErrorCode.UNAUTHORIZED, "该链接失效");
            }
        }
        return BaseResponse.success();
    }

    @Data
    private static class PasswordExchange implements Serializable {

        private static final long serialVersionUID = 1870469175696815105L;
        @ApiModelProperty("token")
        private String token;

        @ApiModelProperty("新密码")
        private String password;
    }
}
